/*
 * Copyright 2002-2021 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.context.event;

import java.util.concurrent.Executor;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.PayloadApplicationEvent;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.util.ErrorHandler;

/**
 * Simple implementation of the {@link ApplicationEventMulticaster} interface.
 *	继承体系：
 *							                     Aware
 *	ApplicationEventMulticaster		BeanFactoryAware	BeanClassLoaderAware
 *						AbstractApplicationEventMulticaster
 *						SimpleApplicationEventMulticaster
 *	ApplicationEventMulticaster	：应用事件广播器接口
 * 将所有事件多播给所有注册的侦听器，让侦听器忽略他们不感兴趣的事件。侦听器通常会对传入的事件对象执行相应的instanceof检查。
 * 默认情况下，所有侦听器都在调用线程中调用。 这允许流氓侦听器阻塞整个应用程序的危险，
 * 但增加了最小的开销。 指定替代任务执行器以在不同线程中执行侦听器，例如从线程池中执行。
 *
 *
 * 总结一下：
 * 1. spring应用事件封装要处理的对象，ApplicationEvent应用事件。
 * 2. 通过应用监听器 ApplicationListener 泛型类，扩展ApplicationEvent应用事件。
 * 3. 通过 应用监听器 扩展类自定义，操作 应用事件 对象中处理对象。
 *
 * 设计模式：观察者模式：一个有改变，通知所有的应用监听器做对应的处理。
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Stephane Nicoll
 * @author Brian Clozel
 * @see #setTaskExecutor
 */
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

	@Nullable
	private Executor taskExecutor;

	@Nullable
	private ErrorHandler errorHandler;

	@Nullable
	private volatile Log lazyLogger;


	/**
	 * 创建新的SimpleApplicationEventMulticaster。
	 */
	public SimpleApplicationEventMulticaster() {
	}

	/**
	 * 为给定的BeanFactory创建新的SimpleApplicationEventMulticaster。
	 */
	public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
		setBeanFactory(beanFactory);
	}


	/**
	 * 设置一个自定义执行器（通常是org.springframework.core.task.TaskExecutor ）来调用每个侦听器。
	 * 默认相当于org.springframework.core.task.SyncTaskExecutor ，在调用线程中同步执行所有监听器。
	 * 考虑在此处指定一个异步任务执行器，以在所有侦听器执行完毕之前不阻塞调用者。
	 * 但是，请注意异步执行不会参与调用者的线程上下文（类加载器、事务关联），除非 TaskExecutor 明确支持这一点。
	 * @see org.springframework.core.task.SyncTaskExecutor
	 * @see org.springframework.core.task.SimpleAsyncTaskExecutor
	 */
	public void setTaskExecutor(@Nullable Executor taskExecutor) {
		this.taskExecutor = taskExecutor;
	}

	/**
	 * 返回当前事件派发器的线程池
	 */
	@Nullable
	protected Executor getTaskExecutor() {
		return this.taskExecutor;
	}

	/**
	 * 设置ErrorHandler以在侦听器抛出异常时调用。
	 * 默认为无，侦听器异常停止当前多播并传播到当前事件的发布者。
	 * 如果指定了任务执行器，则每个单独的侦听器异常将传播到执行器，但不一定会停止其他侦听器的执行。
	 * 考虑设置一个捕获和记录异常的ErrorHandler实现
	 * （a la org.springframework.scheduling.support.TaskUtils.LOG_AND_SUPPRESS_ERROR_HANDLER ）
	 * 或一个记录异常同时传播它们的实现
	 * （例如org.springframework.scheduling.support.TaskUtils.LOG_AND_PROPAGATE_ERROR_HANDLER ）
	 * and logs exceptions
	 */
	public void setErrorHandler(@Nullable ErrorHandler errorHandler) {
		this.errorHandler = errorHandler;
	}

	/**
	 * 返回当前事件派发器的错误处理器
	 * @since 4.1
	 */
	@Nullable
	protected ErrorHandler getErrorHandler() {
		return this.errorHandler;
	}
	/**发布一个默认的事件*/
	@Override
	public void multicastEvent(ApplicationEvent event) {
		multicastEvent(event, resolveDefaultEventType(event));
	}
	/**
	* 发布一个指定事件类型的事件派发器
	*/
	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		/*事件类型为空就是用默认的事件类型解析器*/
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		/*获取事件多波器的线程池*/
		Executor executor = getTaskExecutor();
		/*拿到当前事件的所有监听器，伦轮训所有的监听器，对事件进行派发。*/
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

	private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
		return ResolvableType.forInstance(event);
	}

	/**
	 * Invoke the given listener with the given event.
	 * @param listener the ApplicationListener to invoke
	 * @param event the current event to propagate
	 * @since 4.1
	 */
	protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
		/*获取到错误处理器的引用*/
		ErrorHandler errorHandler = getErrorHandler();
		if (errorHandler != null) {
			try {
				/*真正执行派发事件的逻辑*/
				doInvokeListener(listener, event);
			}
			catch (Throwable err) {
				errorHandler.handleError(err);
			}
		}
		else {
			doInvokeListener(listener, event);
		}
	}

	@SuppressWarnings({"rawtypes", "unchecked"})
	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
		try {
			/*监听器发布事件*/
			listener.onApplicationEvent(event);
		}
		catch (ClassCastException ex) {
			String msg = ex.getMessage();
			if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
					(event instanceof PayloadApplicationEvent &&
							matchesClassCastMessage(msg, ((PayloadApplicationEvent) event).getPayload().getClass()))) {
				// Possibly a lambda-defined listener which we could not resolve the generic event type for
				// -> let's suppress the exception.
				Log loggerToUse = this.lazyLogger;
				if (loggerToUse == null) {
					loggerToUse = LogFactory.getLog(getClass());
					this.lazyLogger = loggerToUse;
				}
				if (loggerToUse.isTraceEnabled()) {
					loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
				}
			}
			else {
				throw ex;
			}
		}
	}
	/*发生异常时相关的处理逻辑*/
	private boolean matchesClassCastMessage(String classCastMessage, Class<?> eventClass) {
		// On Java 8, the message starts with the class name: "java.lang.String cannot be cast..."
		if (classCastMessage.startsWith(eventClass.getName())) {
			return true;
		}
		// On Java 11, the message starts with "class ..." a.k.a. Class.toString()
		if (classCastMessage.startsWith(eventClass.toString())) {
			return true;
		}
		// On Java 9, the message used to contain the module name: "java.base/java.lang.String cannot be cast..."
		int moduleSeparatorIndex = classCastMessage.indexOf('/');
		if (moduleSeparatorIndex != -1 && classCastMessage.startsWith(eventClass.getName(), moduleSeparatorIndex + 1)) {
			return true;
		}
		// Assuming an unrelated class cast failure...
		return false;
	}

}
